package event.model;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Observable;

import javax.swing.Timer;

import keyboard.model.Login;

public class NarwhalEvent extends Observable implements ActionListener, Login {

	public static final int NO_USER = 0;
	public static final int ALREADY_REGISTERED = 1;
	public static final int REGISTERED = 2;
	public static final int EVENT_FULL = 3;
	public static final int EVENT_ONLY_FUNK = 4;
	private static final int ATTENDING = -1;
	private static final int NOT_ACCEPTED = -2;
	private static final int NOT_ATTENDING = -3;

	private ArrayList<Event> events;
	private Event active;
	private Database db;
	private User blippedCard;
	private User loggedIn;
	private Timer t;
	
	public NarwhalEvent() {
		events = new ArrayList<Event>();
		db = new Database();
		t = new Timer(5000,this);
		update();
	}

	public ArrayList<Integer> getEventIndexes() {
		ArrayList<Integer> answer = new ArrayList<Integer>();
		for (Event e : events)
			answer.add(e.id);
		return answer;
	}

	public String getTitle(int event) {
		for (Event e : events)
			if (e.id == event)
				return e.title;
		return null;
	}

	public void setActive(int index) {
		for (Event e : events) {
			if (e.id == index)
				active = e;
		}
	}

	public String getActiveTitle() {
		return active.title;
	}

	public String getActiveBody() {
		return active.body;
	}

	public String getActiveArranger() {
		return active.user.toString();
	}

	public void update() {
		t.stop();
		System.out.println("Updating events...");
		ArrayList<Event> events = new ArrayList<Event>();
		String sql = "SELECT * FROM registration_events WHERE (opens <= UNIX_TIMESTAMP() AND closes >= UNIX_TIMESTAMP() )";
		ResultSet answer = db.query(sql);
		try {
			while (answer.next()) {
				Event e = new Event();
				e.id = answer.getInt("id");
				e.title = answer.getString("title");
				e.body = answer.getString("description");
				e.user = createUser(answer.getInt("responsible"));
				e.occures = new Time(answer.getLong("begins") * 1000);
				e.closes = new Time(answer.getLong("locks") * 1000);
				e.approval = answer.getString("requireApproval").equals("yes");
				e.requireFunkis = answer.getString("funkonly").equals("yes");
				e.limit = answer.getInt("limit");
				events.add(e);
			}
		} catch (SQLException e) {
			System.out.println(sql);
			System.err.println(sql);
			e.printStackTrace();
		}
		this.events = events;
		System.out.println("Update done!");
		setChanged();
		notifyObservers();
		t.restart();
	}
	
	private boolean isFunkis() {
		if (blippedCard == null)
			return false;
		String sql = "SELECT id FROM staff WHERE person = " + blippedCard.id + " AND quit > UNIX_TIMESTAMP() LIMIT 1";  
		ResultSet answer = db.query(sql);
		
		try {
			return answer.next();
		} catch (SQLException e) {
			System.err.println(sql);
			e.printStackTrace();
			return false;
		}
		
		
	}

	private User createUser(int id) {
		String sql = "SELECT * FROM members WHERE id=" + id + " LIMIT 1";
		ResultSet answer = db.query(sql);

		try {
			answer.next();
			String firstname = answer.getString("firstname");
			String lastname = answer.getString("lastname");
			String nickname = answer.getString("nickname");
			User u = new User(firstname, lastname, nickname);
			u.allergies = answer.getString("allergies");
			u.id = answer.getInt("id");
			return u;
		} catch (SQLException e) {
			System.err.println(sql);
			e.printStackTrace();
			return null;
		}
	}

	public String getActiveOccures() {
		return active.occures.toString();
	}

	public String getActiveCloses() {
		return active.closes.toString();
	}

	public boolean isActiveClosed() {
		return active.isClosed();
	}

	public void setCard(String card) {
		String sql = "SELECT user_id FROM rfid WHERE rfid = " + card
				+ " LIMIT 1";
		ResultSet answer = db.query(sql);
		try {
			if (answer.next()) {
				blippedCard = createUser(answer.getInt("user_id"));
				sql = "UPDATE rfid SET last_used = UNIX_TIMESTAMP() WHERE rfid = "
						+ card;
				db.update(sql);
			} else {
				blippedCard = null;
			}
		} catch (SQLException e) {
			System.err.println(sql);
			e.printStackTrace();
		}

	}

	public String getBlippedUser() {
		if (blippedCard == null)
			return "";
		return blippedCard.toString();
	}

	public void clearBlipp() {
		blippedCard = null;
	}

	public int register() {
		if (blippedCard == null)
			return NO_USER;
		
		switch (attendingStatus()) {
		case ATTENDING:
		case NOT_ACCEPTED:
			return ALREADY_REGISTERED;
		}
		if (active.requireFunkis && !isFunkis())
			return EVENT_ONLY_FUNK;
		if (!placesLeft()) 
			return EVENT_FULL;
		
		int event = active.id;
		int person = blippedCard.id;
		String allergies = blippedCard.allergies;
		String comment = "---Added from the wallpc Narwhal!---";
		String approved = active.approval ? "no" : "yes";
		
		String query = "INSERT INTO registration_registrations (person, event, registrationdate, allergies, comment, approved) "
				+ "VALUES ("
				+ person
				+ ", "
				+ event
				+ ", UNIX_TIMESTAMP() , '"
				+ allergies
				+ "', '"
				+ comment
				+ "', '"
				+ approved
				+ "')";
		db.update(query);
		return REGISTERED;
	}

	public boolean placesLeft() {
		if (active == null)
			return false;
		if (active.limit == 0)
			return true;
		String sql = "SELECT COUNT(*) AS going FROM registration_registrations WHERE event = " + active.id;
		ResultSet answer = db.query(sql);
		try {
			answer.next();
			return answer.getInt("going") < active.limit;
		} catch (SQLException e) {
			System.err.println(sql);
			e.printStackTrace();
			return false;
		}
	}
	
	private int attendingStatus() {
		int event = active.id;
		int person = blippedCard.id;
		String query = "SELECT approved FROM registration_registrations WHERE person = " + person + " AND event = " + event + " LIMIT 1";
		
		ResultSet answer = db.query(query);
		
		try {
			if (answer.next()) {
				return answer.getString("approved").equals("yes") ? ATTENDING : NOT_ACCEPTED;
			}
		} catch (SQLException e1) {
			e1.printStackTrace();
		}
		return NOT_ATTENDING;
		
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		update();
	}

	public String getBlippedFirstName() {
		if (blippedCard == null)
			return null;
		return blippedCard.firstName;
	}

	@Override
	public boolean login(String username, String password) {
		if (username == null || username == "")
			return false;
		String sql = "SELECT id, password FROM members WHERE login = '"+username+ "' LIMIT 1";
		ResultSet answer = db.query(sql);
		
		String remotePassword = null;
		
		try {
			if (!answer.next()) {
				return false;
			}
			remotePassword = answer.getString("password");
			if (md5(password).equals(remotePassword)) {
				loggedIn = createUser(answer.getInt("id"));
				System.out.println("Loggade in: " + loggedIn);
				return true;
			}
		} catch (SQLException e) {
			System.err.println(sql);
			e.printStackTrace();
			return false;
		}
		
		return false ;
	}
	
	private String md5(String in) {
		try {
		byte[] bytesOfMessage = in.getBytes("UTF-8");

		MessageDigest md = MessageDigest.getInstance("MD5");
		byte[] thedigest = md.digest(bytesOfMessage);
		
		byte[] ny = new byte[17];
		for (int i = 0; i < 16; i++) {
			ny[i+1] = thedigest[i];
		}
		String generated = new BigInteger(ny).toString(16);
		return generated;
		} catch (Exception e) {
			System.err.println("Error while doing md5, returning \"ERROR\"");
			e.printStackTrace();
			
			return "ERROR";
		}
	}
}
